/*****************************************************************************
*    Ali Corp. All Rights Reserved. 2002 Copyright (C)
*
*    File:    bootloader.c
*
*    Description:    This file contains all globe micros and functions declare
*                    of Flash boot loader.
*    History:
*           Date            Athor        Version          Reason
*       ============    =============   =========   =================
*   1.  Oct.28.2003     Justin Wu       Ver 0.1    Create file.
 *  2.  2006.5.16       Justin Wu       Ver 0.2    STO chunk support & clean up.
*****************************************************************************/
#include <sys_config.h>
#include <basic_types.h>
#include <mediatypes.h>
#include <sys_parameters.h>
#include <os/tds2/itron.h>
#include <osal/osal_timer.h>
#include <api/libc/printf.h>
#include <api/libc/string.h>
#include <api/libchunk/chunk.h>
#include <osal/osal.h>
#include <hal/hal_mem.h>
#include <hal/hal_gpio.h>
#include <bus/i2c/i2c.h>
#include <bus/sci/sci.h>
#include <bus/tsi/tsi.h>
#include <bus/pinmux/pinmux.h>
#include <hld/pan/pan.h>
#include <hld/pan/pan_key.h>
#include <hld/hld_dev.h>
#include <hld/sto/sto.h>
#include <hld/sto/sto_dev.h>
#include <hld/dis/vpo.h>
#include <hld/decv/decv.h>
#include <hld/rfm/rfm.h>
#include <api/libc/alloc.h>
#include <sys_parameters.h>
#include <bus/flash/flash.h>
#include <hal/hal_gpio.h>
#include <hal/hal_mem.h>
#include <hld/pan/pan_dev.h>
#include <hld/smc/smc.h>
#include <hld/pan/pan.h>
#include <bus/i2c/i2c.h>
#include <bus/otp/otp.h>
#include <api/libloader/ld_boot_info.h>
#include <api/librsa/rsa_verify.h>
#include <hld/scart/Scart.h>
#include "tve_hd_setting_half_mode.h"
#include "system_data.h"




#define _OTA_E_
#define US_TICKS        (sys_ic_get_cpu_clock()*1000000 / 2000000)
#define WAIT_300MS      (300000 * US_TICKS)

#ifdef FIXED_PRINTF
#undef FIXED_PRINTF
#endif
#define FIXED_PRINTF(...)     do{}while(0)
//#define FIXED_PRINTF     libc_printf
#define PRINTF_BOOTLOGO(a,b)    FIXED_PRINTF("The "#a" = 0x%08x,The "#b" = 0x%08x\n",(UINT32)(a),(UINT32)(b))

#define SECTOR_OFFSET_BIT 16
#define FLASH_SECTOR_SIZE (64*1024)
#define OTA_SIZE 15
#define UK_SIZE 16
#define HW_SET_GPIO 0x104

/* Calcuate InternalBufferSize for 7-zip */
#define LZMA_BASE_SIZE  1846
#define LZMA_LIT_SIZE   768
#define BUFFER_SIZE     ((LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (0 + 2))) * sizeof(UINT16))

#define OTA_SEE_CODE  3
#define OTA_CPU_CODE  2
#define SEE_CODE  1
#define MAIN_CODE 0
#define MAIN_ENTRY 0x80000200


#ifdef __mips16
#define SDBBP()		asm volatile(".half 0x17ff; \
								  nop")
#else
#define SDBBP()		asm volatile(".word	0x1000ffff; \
								  nop");
#endif

#define CB_LEVEL_PAL_SD				0x85
#define CB_LEVEL_NTSC_SD            0x85
#define CR_LEVEL_PAL_SD				0x55
#define CR_LEVEL_NTSC_SD			0x55
#define LUMA_LEVEL_PAL_SD			0x52
#define LUMA_LEVEL_NTSC_SD			0x4e
#define CHRMA_LEVEL_PAL_SD			0x0c
#define CHRMA_LEVEL_NTSC_SD		    0x0c
#define FREQ_RESPONSE_PAL_SD		0x102
#define FREQ_RESPONSE_NTSC_SD		0x102

extern int un7zip(UINT8 *, UINT8 *, UINT8 *);
extern void __SEE_ROM_START();
extern void __SEE_ROM_END();

#if (SYS_MAIN_BOARD == BOARD_DB_M3603_02V01)
struct pan_hw_info pan_hw_info =
{
	0,				/* type_kb : 2; Key board (array) type */
	1,				/* type_scan : 1; 0: Slot scan, 1: Shadow scan */
	1,				/* type_key: 1; Key exit or not */
	1,				/* type_irp: 3; 0: not IRP, 1: NEC, 2: LAB */
	0,				/* type_mcu: 1; MCU exit or not */
	4,				/* num_com: 4; Number of com PIN, 0 to 8 */
	1,				/* Position of colon flag, 0 to 7 */
	1,				/* num_scan: 2; Number of scan PIN, 0 to 2 */
	0,				/* rsvd_bits:6; Reserved bits */
	0,              /* rsvd byte for align pan_info */
	{0, HAL_GPIO_O_DIR, 127},		/* LATCH PIN */
	{0, HAL_GPIO_O_DIR, 	FP_CLOCK_GPIO_NUM},		/* CLOCK PIN */
	{1, HAL_GPIO_O_DIR, 	FP_DATA_GPIO_NUM},		/* DATA PIN */
	{{0, HAL_GPIO_I_DIR, 	FP_KEY1_GPIO_NUM},		/* SCAN1 PIN */
	{0, HAL_GPIO_I_DIR, 127}},		/* SCAN2 PIN */
	{{0, HAL_GPIO_O_DIR, 	FP_COM1_GPIO_NUM},		/* COM1 PIN */
	{0, HAL_GPIO_O_DIR, 	FP_COM2_GPIO_NUM},		/* COM2 PIN */
	{0, HAL_GPIO_O_DIR, 	FP_COM3_GPIO_NUM},		/* COM3 PIN */
	{0, HAL_GPIO_O_DIR, 	FP_COM4_GPIO_NUM},		/* COM4 PIN */
	{0, HAL_GPIO_O_DIR, 127},		/* COM5 PIN */
	{0, HAL_GPIO_O_DIR, 127},		/* COM6 PIN */
	{0, HAL_GPIO_O_DIR, 127},		/* COM7 PIN */
	{0, HAL_GPIO_O_DIR, 127}},		/* COM8 PIN */
	{{0, HAL_GPIO_O_DIR, 	FP_STANDBY_GPIO_NUM},		/* POWER PIN */
	{1, HAL_GPIO_O_DIR, 	FP_LOCK_GPIO_NUM},		/* LOCK PIN */
	{0, HAL_GPIO_O_DIR, 127},		/* Extend function LBD */
	{0, HAL_GPIO_O_DIR, 127}},		/* Extend function LBD */
    {0, HAL_GPIO_O_DIR, 127},       /* rsvd extend function LBD */        
	300,							/* Intv repeat first */
	250,							/* Intv repeat */
	350,							    /* Intv release, 0: disable release key */
	NULL,	 	 	 	 	 	 	/* hook_scan() callback */
	NULL,	 	 	 	 	 	 	/* hook_show() callback */
};
#else
struct pan_hw_info pan_hw_info =
{
	0,				/* type_kb : 2; Key board (array) type */
	1,				/* type_scan : 1; 0: Slot scan, 1: Shadow scan */
	1,				/* type_key: 1; Key exit or not */
	1,				/* type_irp: 3; 0: not IRP, 1: NEC, 2: LAB */
	0,				/* type_mcu: 1; MCU exit or not */
	4,				/* num_com: 4; Number of com PIN, 0 to 8 */
	1,				/* Position of colon flag, 0 to 7 */
	1,				/* num_scan: 2; Number of scan PIN, 0 to 2 */
	0,				/* rsvd_bits:6; Reserved bits */
	0,              /* rsvd byte for align pan_info */
	{0, HAL_GPIO_O_DIR,     95},		/* LATCH PIN */
	{0, HAL_GPIO_O_DIR, 	FP_CLOCK_GPIO_NUM},		/* CLOCK PIN */
	{1, HAL_GPIO_O_DIR, 	FP_DATA_GPIO_NUM},		/* DATA PIN */
	{{0, HAL_GPIO_I_DIR, 	FP_KEY1_GPIO_NUM},		/* SCAN1 PIN */
	{0, HAL_GPIO_I_DIR, 0x3fff}},		/* SCAN2 PIN */
	{{0, HAL_GPIO_O_DIR, 	FP_COM1_GPIO_NUM},		/* COM1 PIN */
	{0, HAL_GPIO_O_DIR, 	FP_COM2_GPIO_NUM},		/* COM2 PIN */
	{0, HAL_GPIO_O_DIR, 	FP_COM3_GPIO_NUM},		/* COM3 PIN */
	{0, HAL_GPIO_O_DIR, 	FP_COM4_GPIO_NUM},		/* COM4 PIN */
	{0, HAL_GPIO_O_DIR, 0x3fff},		/* COM5 PIN */
	{0, HAL_GPIO_O_DIR, 0x3fff},		/* COM6 PIN */
	{0, HAL_GPIO_O_DIR, 0x3fff},		/* COM7 PIN */
	{0, HAL_GPIO_O_DIR, 0x3fff}},		/* COM8 PIN */
	{{0, HAL_GPIO_O_DIR, 	FP_STANDBY_GPIO_NUM},		/* POWER PIN */
	{1, HAL_GPIO_O_DIR, 	FP_LOCK_GPIO_NUM},		/* LOCK PIN */
	{0, HAL_GPIO_O_DIR, 0x3fff},		/* Extend function LBD */
	{0, HAL_GPIO_O_DIR, 0x3fff}},		/* Extend function LBD */
    {0, HAL_GPIO_O_DIR, 0x3fff},       /* rsvd extend function LBD */        
	300,							/* Intv repeat first */
	250,							/* Intv repeat */
	350,							    /* Intv release, 0: disable release key */
	NULL,	 	 	 	 	 	 	/* hook_scan() callback */
	NULL,	 	 	 	 	 	 	/* hook_show() callback */
};
#endif
#define bitmap_list				NULL
#define bitmap_list_num		0
struct pan_device *panel_dev;
struct pan_configuration pan_config = {&pan_hw_info, bitmap_list_num, bitmap_list};

static UINT8  g_second_loader = 0;
static UINT8  g_crc_bad = 0;
static UINT32 unzip_length;

struct pan_device *panel_dev = NULL;
struct sto_device *flash_dev = NULL;

UINT8 *g_see_unziped   = NULL;
static void bl_dump_data(UINT8 *data, UINT32 len)
{
#if 0
	UINT32 i;
	for(i=0; i<len; i++)
	{
		FIXED_PRINTF("0x%02x, ", *(data+i));
		if((i+1)%16==0)
			FIXED_PRINTF("\n");
	}
	if(i%16!=0)
		FIXED_PRINTF("\n");
#endif
}

static UINT32 g_ota_offset = 0;
static UINT8 find_second_loader()
{
#ifdef _OTA_E_
#define C_SECTOR_SIZE   0x10000
    UINT8 *buffer;
    UINT32 data_id;
    UINT32 data_len;
    UINT32 data_off;
    UINT32 data_crc;
    UINT32 crc;
    UINT32 pointer = 0;

    UINT8 bSecondOta = 0;

    while(pointer < flash_dev->totol_size)
    {
        data_id  = sto_fetch_long((UINT32)pointer + CHUNK_ID);
        data_len = sto_fetch_long((UINT32)pointer + CHUNK_LENGTH);
        data_off = sto_fetch_long((UINT32)pointer + CHUNK_OFFSET);
        data_crc = sto_fetch_long((UINT32)pointer + CHUNK_CRC);
        if(data_len && (data_len < data_off) && (data_crc != NO_CRC) && ((data_id & CHUNKID_SECLOADER_MASK) == CHUNKID_SECLOADER))
        {
            buffer = (UINT8 *)MALLOC(data_len);
        	if(buffer != NULL)
        	{
    		    sto_get_data(flash_dev, buffer, pointer + 16, data_len);
                crc = MG_Table_Driven_CRC(0xFFFFFFFF, buffer, data_len);
                FREE(buffer);
                if(data_crc == crc)
                {
                    g_ota_offset = pointer;
                    bSecondOta = 1;
                    break;
                }
        	}
        }
	    pointer += C_SECTOR_SIZE;
    }

    //verify the second loader.
    if (bSecondOta)
    {
        pointer = g_ota_offset;
        do
        {
            data_id  = sto_fetch_long((UINT32)pointer + CHUNK_ID);
            data_len = sto_fetch_long((UINT32)pointer + CHUNK_LENGTH);
            data_off = sto_fetch_long((UINT32)pointer + CHUNK_OFFSET);
            data_crc = sto_fetch_long((UINT32)pointer + CHUNK_CRC);

    		FIXED_PRINTF("2.6!\n");
            if (data_off > flash_dev->totol_size)
            {
                FIXED_PRINTF("@pointer[%08X] id[%08X] data_off[%08X] > flash size\n", \
                      pointer, data_id, data_off);
                bSecondOta = 0;
                break;
            }
            if ((data_off != 0) && (data_len > data_off))
            {
                FIXED_PRINTF("@pointer[%08X] id[%08X] data_len[%08X] > data_off[%08X]\n", \
                      pointer, data_id, data_len, data_off);
                bSecondOta = 0;
                break;
            }
    	    if (data_crc != NO_CRC)
            {
    			if ((buffer = (UINT8 *)MALLOC(data_len)) == NULL)
                    ASSERT(0);
                sto_get_data(flash_dev, buffer, pointer + 16, data_len);
                crc = MG_Table_Driven_CRC(0xFFFFFFFF, buffer, data_len);
                FREE(buffer);
    			FIXED_PRINTF("2.7!\n");
                if (data_crc != crc)
                {
                    FIXED_PRINTF("@pointer[%08X] id[%08X] crc[%08X] != data_crc[%08X]\n", \
                        pointer, data_id, crc, data_crc);
                    bSecondOta = 0;
                    break;
                }
            }
            pointer += data_off;
            if (pointer + CHUNK_HEADER_SIZE > flash_dev->totol_size)
            {
                FIXED_PRINTF("@pointer[%08X] no space for header\n", pointer);
                bSecondOta = 0;
                break;
            }

        } while (data_off);
    }
    if (0 == bSecondOta)
        g_ota_offset = 0;
    return bSecondOta;
#endif
    return 0;
}

static UINT8 check_program(void)
{
    UINT32 i;
    UINT8 *buffer;
    UINT32 data_id;
    UINT32 data_len;
    UINT32 data_off;
    UINT32 data_crc;
    UINT32 crc;
    UINT32 pointer = 0;
    g_second_loader = find_second_loader();
    do
    {
        data_id  = sto_fetch_long((UINT32)pointer + CHUNK_ID);
        data_len = sto_fetch_long((UINT32)pointer + CHUNK_LENGTH);
        data_off = sto_fetch_long((UINT32)pointer + CHUNK_OFFSET);
        data_crc = sto_fetch_long((UINT32)pointer + CHUNK_CRC);

        if (pointer != 0)
        {
            if (((data_id >> 16) & 0xFF) + ((data_id >> 24) & 0xFF) != 0xFF)
                return 1;
        }
        if (data_off > flash_dev->totol_size)
        {
            FIXED_PRINTF("@pointer[%08X] id[%08X] data_off[%08X] > flash size\n", \
                  pointer, data_id, data_off);
            return 2;
        }
        if ((data_off != 0) && (data_len > data_off))
        {
            FIXED_PRINTF("@pointer[%08X] id[%08X] data_len[%08X] > data_off[%08X]\n", \
                  pointer, data_id, data_len, data_off);
            return 3;
        }
	    if (data_crc != NO_CRC)
        {
			if ((buffer = (UINT8 *)MALLOC(data_len)) == NULL)
                ASSERT(0);
            sto_get_data(flash_dev, buffer, pointer + 16, data_len);
            crc = MG_Table_Driven_CRC(0xFFFFFFFF, buffer, data_len);
            FREE(buffer);
            if (data_crc != crc)
            {
                FIXED_PRINTF("@pointer[%08X] id[%08X] crc[%08X] != data_crc[%08X]\n", \
                    pointer, data_id, crc, data_crc);
                return 4;
            }
        }
        pointer += data_off;
        if (pointer + CHUNK_HEADER_SIZE > flash_dev->totol_size)
        {
            FIXED_PRINTF("@pointer[%08X] no space for header\n", pointer);
            return 5;
        }

    } while (data_off);

    return 0;
}

BOOL get_backup_ota_addr(UINT32 *block_addr, UINT32 *block_len)//include chunk header
{
	UINT32 chunk_id = 0;
    if(flash_info.flash_size<0x800000)
        return FALSE;
	*block_addr = flash_info.flash_size - OTA_SIZE*FLASH_SECTOR_SIZE;//8M flash
	*block_len = 0;	
	chunk_id = sto_fetch_long(*block_addr);
	FIXED_PRINTF("get_backup_ota_addr, chunk id: 0x%08x\n", chunk_id);
	if(chunk_id != CHUNKID_SECLOADER)
		return FALSE;
	*block_len = sto_fetch_long(*block_addr+CHUNK_LENGTH)+0x10;
	return TRUE;
}

UINT8 *expand_ram(UINT32 addr, UINT32 len, int unzip(UINT8 *, UINT8 *, UINT8 *),UINT32 type)
{    
    UINT8 *buffer;
    UINT8 *codeentry;
	UINT32 i=0;

	if(type == MAIN_CODE || type == OTA_CPU_CODE)
		codeentry = (UINT8 *)MAIN_ENTRY;
	else if(type == SEE_CODE || type == OTA_SEE_CODE)
		codeentry = g_see_unziped;

	buffer = MALLOC(BUFFER_SIZE);
    if (buffer == NULL)
    {
        FIXED_PRINTF("Boot loader: No decompress buffer!\n");
		return 0;
    }

	if (unzip((void *)(addr), codeentry, buffer) != 0)
	{
		codeentry = 0;
		FIXED_PRINTF("Boot loader: error to decompress chunk(type %d)!\n",type);
	}
	else
	{
		unzip_length = *(UINT32*)buffer;
	}	

    FREE(buffer);
    return codeentry;
}

void set_os_config(UINT16 task_num, UINT16 sema_num, UINT16 flg_num, UINT16 mbf_num, UINT16 mutex_num)
{
    struct os_config *ptr = (struct os_config *)0xa00001e0;

    ptr->task_num = task_num;
    ptr->sema_num = sema_num;
    ptr->flg_num = flg_num;
    ptr->mbf_num = mbf_num;
    ptr->mutex_num = mutex_num;
    ptr->parity_value = ptr->task_num + ptr->sema_num + ptr->flg_num + ptr->mbf_num + ptr->mutex_num;
}


void bl_GPIO_init()
{
     // disable all GPIO, except DDR power control gpio
	*((unsigned long *)0xb8000430) =
		(DDR_POWER_CTL_GPIO_POS < 32) ? (1 << DDR_POWER_CTL_GPIO_POS) : 0;	
	*((unsigned long *)0xb8000434) =
		((DDR_POWER_CTL_GPIO_POS >= 32) && (DDR_POWER_CTL_GPIO_POS < 64)) ?
		(1 << (DDR_POWER_CTL_GPIO_POS - 32)) : 0;	
	*((unsigned long *)0xb8000438) =
		((DDR_POWER_CTL_GPIO_POS >= 64) && (DDR_POWER_CTL_GPIO_POS < 96)) ?
		(1 << (DDR_POWER_CTL_GPIO_POS - 64)) : 0;	
	*((unsigned long *)0xb800043c) =
		((DDR_POWER_CTL_GPIO_POS >= 96) && (DDR_POWER_CTL_GPIO_POS < 128)) ?
		(1 << (DDR_POWER_CTL_GPIO_POS - 96)) : 0;
	*((unsigned long *)0xb8000440) =
		((DDR_POWER_CTL_GPIO_POS >= 128) && (DDR_POWER_CTL_GPIO_POS < 160)) ?
		(1 << (DDR_POWER_CTL_GPIO_POS - 128)) : 0;
#if (SYS_MAIN_BOARD == BOARD_DB_M3603_02V01)
    UINT32 data;
    // disable all GPIO, except DDR power control gpio
    *((unsigned long *)0xb8000430) = 0;	// GPIO 0~31
    *((unsigned long *)0xb8000434) = 0;	// GPIO 32~63
    *((unsigned long *)0xb8000438) = 0;	// GPIO 64~95
    *((unsigned long *)0xb800043c) = 0;	// GPIO 96~127
    *((unsigned long *)0xb8000440) = 0;

	data = *((unsigned long *)0xb8000430);
	data |= (1 << 4);  // GPIO4 for FP_LOCK
	data |= (1 << 5);  // GPIO5 for Tuner Reset
	data |= (1 << 10);  // GPIO10 for HDMI SDA
	data |= (1 << 11);  // GPIO11 for HDMI SCL
    data |= (1 << 0);  // GPIO0     // power
    data |= (1 << 6);  // GPIO6     // mute
    data |= (1 << 24); // GPIO24 for FP_DATA
	*((unsigned long *)0xb8000430) = data;

	//GPIO75
	data = *((unsigned long *)0xb8000434);
	data |= (1 << (59 - 32)); // GPIO59 for FP_COM1
	data |= (1 << (60 - 32)); // GPIO60 for FP_COM2
	data |= (1 << (61 - 32)); // GPIO61 for FP_COM3
	data |= (1 << (62 - 32)); // GPIO62 for FP_COM4
	data |= (1 << (63 - 32)); // GPIO63 for FP_KEY1
	data |= (1 << (46 - 32)); // GPIO46 for FP_CLOCK
	*((unsigned long *)0xb8000434) = data;
	
	data = *((unsigned long *)0xb8000438);
	data |= (1 << (75-64));  // GPIO75: LNB CUT
	*((unsigned long *)0xb8000438) = data;
    data = *((unsigned long *)0xb8000088);
	data |= (1 << 24);  // I2C0
    data |= (1 << 25);  // I2C1 BGA
    data |= (1 << 0);   // for CI
    data |= (1 << 1);   // for CI
    data |= (1 << 2);   // for TSI SPI
	data |= (1 << 14);//smc
	*((unsigned long *)0xb8000088) = data;
	
    data = *((unsigned long *)0xb800008C);
    data |= (1 << 2);   // TSI_SPI sel
    data |= (1 << 3);   // TSI_SPI2 sel
    data |= (1 << 31);  // BGA I2S output sel
    *((unsigned long *)0xb800008C) |= data;
    osal_delay(100);
	HAL_GPIO_BIT_DIR_SET(6, HAL_GPIO_O_DIR);  
#endif    
}
void bl_init_uart()
{
	if(1)
	{
		sci_16550uart_attach(1);	// Use just 1 UART for RS232
		sci_mode_set(SCI_FOR_RS232, 115200, SCI_PARITY_EVEN);
	}
	FIXED_PRINTF("HW BootLoader APP  init!\n");

}

void bl_init_flash()
{
    UINT8  flash_speed;
    //init flash device
	*((unsigned long *)0xb8000080) |=  0x00004000;   //reset flash
	osal_delay(1);
	*((unsigned long *)0xb8000080) =  0x00000000;
	*((unsigned long *)0xb802e098) |=  0xc2000000;  //for flash can read 4M

#ifndef ENABLE_SERIAL_FLASH
	flash_info_pl_init();
	sto_local_flash_attach(NULL);
#else
	flash_info_sl_init();
	sto_local_sflash_attach(NULL);
#endif
    flash_dev = (struct sto_device *)dev_get_by_type(NULL, HLD_DEV_TYPE_STO);
	if (flash_dev == NULL)
	{
		FIXED_PRINTF("Can't find FLASH device!\n");
	}
	sto_open(flash_dev);
	sto_chunk_init(0, flash_dev->totol_size);
	sto_get_data(flash_dev, &flash_speed, HW_SET_FLASHSPEED, 1);
	flash_speed &= 0x3F;
	if (flash_speed == 0)
		flash_speed = HW_FLASH_DEFSPEED;
	HAL_ROM_MODE_SET(flash_speed, 0, 1, 0);
    flash_info.flash_size=0;
    flash_identify();
	FIXED_PRINTF("flash init OK,flash size is:%x!\n",flash_info.flash_size);
    osal_delay(10000);
}
void bl_init_panel()
{
    UINT32 data;
    dev_en_remote(0);
#ifdef PANEL_DISPLAY
#if (SYS_MAIN_BOARD == BOARD_DB_M3603_02V01)
    FIXED_PRINTF("bl pan hwscan attach\n");
    data = *((unsigned long *)0xb8000088);
    data |= (1 << 24);  // I2C0
    data |= (1 << 25);  // I2C1 BGA
	*((unsigned long *)0xb8000088) = data;
	i2c_scb_attach(3);
	i2c_gpio_attach(1);    
    i2c_mode_set(I2C_TYPE_SCB1, 100000, 1);		// SCART/panel
	pan_hwscan_l_attach(&pan_config);
	panel_dev = (struct pan_device *)dev_get_by_id(HLD_DEV_TYPE_PAN, 0);
#else
	/* Init front panel and IR */
    data = *((unsigned long *)0xb8000088);
    data |= (1 << 24);  // I2C0
    data |= (1 << 25);  // I2C1 BGA
	*((unsigned long *)0xb8000088) = data;
	i2c_scb_attach(3);
	i2c_gpio_attach(1);
	i2c_mode_set(I2C_TYPE_SCB1, 100000, 1);		// SCART/panel
	pan_ch455_attach(&pan_config);
   	extern void pan_ch455_id_set(struct pan_device *dev, UINT32 id);
    panel_dev = (struct pan_device *)dev_get_by_id(HLD_DEV_TYPE_PAN, 0);
    pan_ch455_id_set(panel_dev,I2C_TYPE_SCB1);
#endif
    if(panel_dev==NULL)
    {
        FIXED_PRINTF("panel attach fail!\n");
        return;
    }
    pan_open(panel_dev);
	pan_display(panel_dev, " ON ", 4);
#endif
	dev_en_remote(1);
    FIXED_PRINTF("panel init OK!\n");
}

/************For BootLogo add*******************/
T_VBIRequest VBIRequest;
struct vdec_device*  g_decv_dev = NULL;
//struct vdec_device*  g_decv_avc_dev = NULL;
//struct vdec_device*  g_decv_dev2 = NULL;
struct vpo_device*   g_vpo_dev = NULL;
struct vpo_device*   g_sd_vpo_dev = NULL;


void avStart()
{
	struct VDecPIPInfo vInitInfo;
	struct MPSource_CallBack vMPCallBack;
	struct PIPSource_CallBack vPIPCallBack;
	struct VDec_PullDown_Opr tPullDownCallBack;
    struct vp_win_config_para win_para;
	
	vdec_profile_level(g_decv_dev, MP_HL, NULL);
	enum TVSystem  tvsys;
	vpo_ioctl(g_vpo_dev, VPO_IO_GET_OUT_MODE, (UINT32) &tvsys);
	
	vInitInfo.adv_setting.init_mode =0;
	vInitInfo.adv_setting.out_sys = tvsys;
    if(tvsys == LINE_720_30)
    {
        vInitInfo.adv_setting.bprogressive = TRUE;
    }

	vdec_set_output(g_decv_dev,	MP_MODE, &vInitInfo, &vMPCallBack, &vPIPCallBack);
	vpo_win_mode(g_vpo_dev, VPO_MAINWIN, &vMPCallBack, &vPIPCallBack);

	vdec_sync_mode(g_decv_dev, 0x00,VDEC_SYNC_I|VDEC_SYNC_P|VDEC_SYNC_B);

}


void InitVPPara_sd(struct VP_InitInfo *pVPInitInfo)
{
	int i;

	MEMSET(pVPInitInfo, 0, sizeof(struct VP_InitInfo));

    pVPInitInfo->device_priority = VPO_AUTO_DUAL_OUTPUT;    // S3602F use VCAP
	//api set backgound color]
	pVPInitInfo->tInitColor.uY = 0x10;
	pVPInitInfo->tInitColor.uCb= 0x80;
	pVPInitInfo->tInitColor.uCr= 0x80;
	//set advanced control
	pVPInitInfo->bBrightnessValue = 0;
	pVPInitInfo->fBrightnessValueSign = TRUE;
	pVPInitInfo->wContrastValue = 0;
	pVPInitInfo->fContrastSign = TRUE;
	pVPInitInfo->wSaturationValue = 0;
	pVPInitInfo->fSaturationValueSign = TRUE;
	pVPInitInfo->wSharpness = 0;
	pVPInitInfo->fSharpnessSign = TRUE;
	pVPInitInfo->wHueSin = 0;
	pVPInitInfo->fHueSinSign = TRUE;
	pVPInitInfo->wHueCos = 0;
	pVPInitInfo->fHueCosSign = TRUE;
	//VPO_Zoom
	pVPInitInfo->tSrcRect.uStartX = 0;
	pVPInitInfo->tSrcRect.uWidth= PICTURE_WIDTH;
	pVPInitInfo->tSrcRect.uStartY= 0;
	pVPInitInfo->tSrcRect.uHeight= PICTURE_HEIGHT;
	pVPInitInfo->DstRect.uStartX = 0;
	pVPInitInfo->DstRect.uWidth= SCREEN_WIDTH;
	pVPInitInfo->DstRect.uStartY= 0;
	pVPInitInfo->DstRect.uHeight= SCREEN_HEIGHT;

	//VPO_SetAspect
	pVPInitInfo->eTVAspect = TV_4_3;
	pVPInitInfo->eDisplayMode = NORMAL_SCALE;//LETTERBOX;
	pVPInitInfo->uNonlinearChangePoint = 111;
	pVPInitInfo->uPanScanOffset = 90;
	//VPO_SetOutput
	for(i=0;i<VP_DAC_TYPENUM;i++)
		pVPInitInfo->pDacConfig[i].bEnable = FALSE;

//CVBS_1

   	pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].bEnable = TRUE;


    pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].tDacIndex.uDacFirst = CVBS_DAC;

	pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].eVGAMode= VGA_NOT_USE;
	pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].bProgressive= FALSE;

	pVPInitInfo->pDacConfig[YUV_1].bEnable = FALSE;

	//RGB
	pVPInitInfo->pDacConfig[VDAC_USE_RGB_TYPE].bEnable = FALSE;

	pVPInitInfo->eTVSys = PAL;

	pVPInitInfo->bWinOnOff = FALSE;

	pVPInitInfo->uWinMode = VPO_MAINWIN;//|VPO_PIPWIN;
	pVPInitInfo->tPIPCallBack.RequestCallback = NULL;
	pVPInitInfo->tPIPCallBack.ReleaseCallback= NULL;
	pVPInitInfo->pSrcChange_CallBack=NULL;
}


void InitVPPara(struct VP_InitInfo *pVPInitInfo)
{
	int i;
    BOOL vdac_progressive = FALSE;

	//api set backgound color]
	pVPInitInfo->tInitColor.uY = 0x10;
	pVPInitInfo->tInitColor.uCb= 0x80;
	pVPInitInfo->tInitColor.uCr= 0x80;

	//set advanced control
	pVPInitInfo->bBrightnessValue = 0;
	pVPInitInfo->fBrightnessValueSign = TRUE;
	pVPInitInfo->wContrastValue = 0;
	pVPInitInfo->fContrastSign = TRUE;
	pVPInitInfo->wSaturationValue = 0;
	pVPInitInfo->fSaturationValueSign = TRUE;
	pVPInitInfo->wSharpness = 0;
	pVPInitInfo->fSharpnessSign = TRUE;
	pVPInitInfo->wHueSin = 0;
	pVPInitInfo->fHueSinSign = TRUE;
	pVPInitInfo->wHueCos = 0;
	pVPInitInfo->fHueCosSign = TRUE;
	pVPInitInfo->bCCIR656Enable = FALSE;
	//VPO_Zoom
	pVPInitInfo->tSrcRect.uStartX = 0;
	pVPInitInfo->tSrcRect.uWidth= PICTURE_WIDTH;
	pVPInitInfo->tSrcRect.uStartY= 0;
	pVPInitInfo->tSrcRect.uHeight= PICTURE_HEIGHT;
	pVPInitInfo->DstRect.uStartX = 0;
	pVPInitInfo->DstRect.uWidth= SCREEN_WIDTH;
	pVPInitInfo->DstRect.uStartY= 0;
	pVPInitInfo->DstRect.uHeight= SCREEN_HEIGHT;

	//VPO_SetAspect
	pVPInitInfo->eTVAspect = TV_4_3;
	pVPInitInfo->eDisplayMode = NORMAL_SCALE;//LETTERBOX;
	pVPInitInfo->uNonlinearChangePoint = 111;
	pVPInitInfo->uPanScanOffset = 90;
	//VPO_SetOutput
	for(i=0;i<VP_DAC_TYPENUM;i++)
		pVPInitInfo->pDacConfig[i].bEnable = FALSE;

	pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].bEnable = FALSE;
	pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].tDacIndex.uDacFirst = CVBS_DAC;
	pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].eVGAMode= VGA_NOT_USE;
	pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].bProgressive= FALSE;

	pVPInitInfo->pDacConfig[YUV_1].bEnable = TRUE;
	pVPInitInfo->pDacConfig[YUV_1].tDacIndex.uDacFirst = YUV_DAC_Y;
	pVPInitInfo->pDacConfig[YUV_1].tDacIndex.uDacSecond= YUV_DAC_U;
	pVPInitInfo->pDacConfig[YUV_1].tDacIndex.uDacThird= YUV_DAC_V;
	pVPInitInfo->pDacConfig[YUV_1].eVGAMode= VGA_NOT_USE;
	pVPInitInfo->pDacConfig[YUV_1].bProgressive= FALSE;

	pVPInitInfo->pDacConfig[VDAC_USE_RGB_TYPE].bEnable = FALSE;
	pVPInitInfo->pDacConfig[VDAC_USE_RGB_TYPE].tDacIndex.uDacFirst = RGB_DAC_R;
	pVPInitInfo->pDacConfig[VDAC_USE_RGB_TYPE].tDacIndex.uDacSecond= RGB_DAC_G;
	pVPInitInfo->pDacConfig[VDAC_USE_RGB_TYPE].tDacIndex.uDacThird= RGB_DAC_B;
	pVPInitInfo->pDacConfig[VDAC_USE_RGB_TYPE].eVGAMode= VGA_NOT_USE;
	pVPInitInfo->pDacConfig[VDAC_USE_RGB_TYPE].bProgressive= FALSE;

    pVPInitInfo->eTVSys = LINE_1080_25;
	pVPInitInfo->pDacConfig[VDAC_USE_CVBS_TYPE].bEnable = TRUE;

	pVPInitInfo->pDacConfig[VDAC_USE_YUV_TYPE].bEnable = FALSE;

	pVPInitInfo->pDacConfig[VDAC_USE_RGB_TYPE].bEnable = TRUE;

	pVPInitInfo->bWinOnOff = FALSE;
	pVPInitInfo->uWinMode = VPO_MAINWIN;//|VPO_PIPWIN;
	pVPInitInfo->tPIPCallBack.RequestCallback = NULL;
	pVPInitInfo->tPIPCallBack.ReleaseCallback= NULL;
	pVPInitInfo->pSrcChange_CallBack=NULL;
}


RET_CODE avInit()
{
	struct VP_InitInfo	tVPInitInfo;


	g_vpo_dev = (struct vpo_device *)dev_get_by_id(HLD_DEV_TYPE_DIS, 0);
    g_sd_vpo_dev = (struct vpo_device *)dev_get_by_id(HLD_DEV_TYPE_DIS, 1);
	g_decv_dev = (struct vdec_device *)dev_get_by_id(HLD_DEV_TYPE_DECV, 0);
	vdec_open(g_decv_dev);
	InitVPPara(&tVPInitInfo);
	vpo_open(g_vpo_dev,&tVPInitInfo);
	InitVPPara_sd(&tVPInitInfo);
	vpo_open(g_sd_vpo_dev,&tVPInitInfo);

	return RET_SUCCESS;
}
/*
struct vdec_avc_config_par vdec_avc_cfg;
void avc_config(void)
{
    vdec_avc_cfg.max_additional_fb_num = MAX_EXTRA_FB_NUM;
    vdec_avc_cfg.memmap.support_multi_bank = FALSE;
    vdec_avc_cfg.memmap.frame_buffer_base = AVC_FB_ADDR;
    vdec_avc_cfg.memmap.frame_buffer_len = AVC_FB_LEN;
    vdec_avc_cfg.memmap.dv_frame_buffer_base = AVC_DVIEW_ADDR;
    vdec_avc_cfg.memmap.dv_frame_buffer_len = AVC_DVIEW_LEN;   
    vdec_avc_cfg.memmap.mv_buffer_base = AVC_MV_ADDR;
    vdec_avc_cfg.memmap.mv_buffer_len = AVC_MV_LEN;
    vdec_avc_cfg.memmap.mb_col_buffer_base = AVC_MB_COL_ADDR;
    vdec_avc_cfg.memmap.mb_col_buffer_len = AVC_MB_COL_LEN;
    vdec_avc_cfg.memmap.mb_neighbour_buffer_base = AVC_MB_NEI_ADDR;
    vdec_avc_cfg.memmap.mb_neighbour_buffer_len = AVC_MB_NEI_LEN;
    vdec_avc_cfg.memmap.cmd_queue_buffer_base = AVC_CMD_QUEUE_ADDR;
    vdec_avc_cfg.memmap.cmd_queue_buffer_len = AVC_CMD_QUEUE_LEN; 
    vdec_avc_cfg.memmap.vbv_buffer_base = (AVC_VBV_ADDR & 0x0fffffff) | 0x80000000;
    vdec_avc_cfg.memmap.vbv_buffer_len = AVC_VBV_LEN;
    vdec_avc_cfg.memmap.laf_rw_buf = AVC_LAF_RW_BUF_ADDR;
    vdec_avc_cfg.memmap.laf_rw_buffer_len = AVC_LAF_RW_BUF_LEN;
    vdec_avc_cfg.memmap.laf_flag_buf = AVC_LAF_FLAG_BUF_ADDR;
    vdec_avc_cfg.memmap.laf_flag_buffer_len = AVC_LAF_FLAG_BUF_LEN;

}
*/

static void vdec_dev_attach(void)
{
	struct vdec_config_par vdec_config_par;

	MEMSET((void *)&vdec_config_par,0,sizeof(struct vdec_config_par));

	//vdec_config_par.mem_map.frm0_Y_size  = 0;
	vdec_config_par.mem_map.frm0_Y_size  = __MM_FB_LEN;
	vdec_config_par.mem_map.frm0_C_size = 0;
	vdec_config_par.mem_map.frm1_Y_size  = 0;
	vdec_config_par.mem_map.frm1_C_size = 0;
	vdec_config_par.mem_map.frm2_Y_size = 0;
	vdec_config_par.mem_map.frm2_C_size = 0;
	vdec_config_par.mem_map.frm0_Y_start_addr = __MM_FB_START_ADDR;
	vdec_config_par.mem_map.frm0_C_start_addr = 0;
	vdec_config_par.mem_map.frm1_Y_start_addr = 0;
	vdec_config_par.mem_map.frm1_C_start_addr = 0;
	vdec_config_par.mem_map.frm2_Y_start_addr = 0;
	vdec_config_par.mem_map.frm2_C_start_addr = 0;
	vdec_config_par.mem_map.dvw_frm_size = 0;
	vdec_config_par.mem_map.dvw_frm_start_addr = 0;
	vdec_config_par.mem_map.maf_size = __MM_MAF_LEN;
	vdec_config_par.mem_map.maf_start_addr = __MM_MAF_START_ADDR;
	vdec_config_par.mem_map.vbv_size = ((__MM_VBV_LEN-4)&0xFFFFFF00);
	vdec_config_par.mem_map.vbv_start_addr = ((__MM_VBV_START_ADDR&0xfffffff)|0x80000000);
	vdec_config_par.mem_map.vbv_end_addr = ((vdec_config_par.mem_map.vbv_start_addr) +  vdec_config_par.mem_map.vbv_size - 1);
	vdec_config_par.user_data_parsing = TRUE; /* macro USER_DATA_PARSING */
	vdec_config_par.dtg_afd_parsing = FALSE; /* macro DTG_AFD_PARSE */
	vdec_config_par.drop_freerun_pic_before_firstpic_show = FALSE; /* macro VDEC27_DROP_FREERUN_BEFORE_FIRSTSHOW */
	vdec_config_par.reset_hw_directly_when_stop = TRUE;  /* macro VDEC27_STOP_REST_HW_DIRECTLY*/
	vdec_config_par.show_hd_service = FALSE;      /* macro SUPPORT_SHOW_HD_SERVICE */
	vdec_config_par.still_frm_in_cc = FALSE;          /* macro STILL_FRAME_IN_CC */
	vdec_config_par.not_show_mosaic = FALSE;      /* macro VDEC_AVOID_MOSAIC_BY_FREEZE_SCR */
	vdec_config_par.adpcm.adpcm_mode = FALSE;  /* macro VIDEO_ADPCM_ONOFF(VIDEO_ADPCM_ON:TRUE VIDEO_ADPCM_OFF:FALSE)*/
	vdec_config_par.adpcm.adpcm_ratio = 0;          
	vdec_config_par.sml_frm.sml_frm_mode = FALSE;  /* macro VDEC27_SML_FRM_ONOFF(VDEC27_SML_FRM_OFF: FALSE   VDEC27_SML_FRM_ON: TRUE)*/
	vdec_config_par.return_multi_freebuf = TRUE;        /* macro VDEC27_SUPPORT_RETURN_MULTI_FREEBUF */ 
	vdec_config_par.sml_frm.sml_frm_size = 0;           /* macro VDEC27_SML_FRM_SIZE*/
	vdec_config_par.lm_shiftthreshold = 2;                   /* macro VDEC27_LM_SHIFTTHRESHOLD*/
	vdec_config_par.vp_init_phase = 0;                        /* macro DEFAULT_MP_FILTER_ENABLE*/
	vdec_config_par.preview_solution = VDEC27_PREVIEW_DE_SCALE; /* macro VDEC27_PREVIEW_SOLUTION(VDEC27_PREVIEW_VE_SCALE or VDEC27_PREVIEW_DE_SCALE)*/
	vdec_m36_attach(&vdec_config_par);
	
    //avc_config();
	//vdec_avc_attach(&vdec_avc_cfg);

}


static struct tve_adjust g_sd_tve_adjust_table[] = {
    {TVE_ADJ_COMPOSITE_Y_DELAY, SYS_625_LINE, 2}, {TVE_ADJ_COMPOSITE_Y_DELAY, SYS_525_LINE, 2},
    {TVE_ADJ_COMPOSITE_C_DELAY, SYS_625_LINE, 0}, {TVE_ADJ_COMPOSITE_C_DELAY, SYS_525_LINE, 0},
    {TVE_ADJ_COMPONENT_Y_DELAY, SYS_625_LINE, 4}, {TVE_ADJ_COMPONENT_Y_DELAY, SYS_525_LINE, 4},
    {TVE_ADJ_COMPONENT_CB_DELAY, SYS_625_LINE, 3}, {TVE_ADJ_COMPONENT_CB_DELAY, SYS_525_LINE, 3},
    {TVE_ADJ_COMPONENT_CR_DELAY, SYS_625_LINE, 1}, {TVE_ADJ_COMPONENT_CR_DELAY, SYS_525_LINE, 1},
    {TVE_ADJ_BURST_LEVEL_ENABLE, SYS_625_LINE, 1}, {TVE_ADJ_BURST_LEVEL_ENABLE, SYS_525_LINE, 0},
    {TVE_ADJ_BURST_CB_LEVEL, SYS_625_LINE, CB_LEVEL_PAL_SD/**/}, {TVE_ADJ_BURST_CB_LEVEL, SYS_525_LINE, CB_LEVEL_NTSC_SD/**/},
    {TVE_ADJ_BURST_CR_LEVEL, SYS_625_LINE, CR_LEVEL_PAL_SD/**/}, {TVE_ADJ_BURST_CR_LEVEL, SYS_525_LINE, CR_LEVEL_NTSC_SD/**/},
    {TVE_ADJ_COMPOSITE_LUMA_LEVEL, SYS_625_LINE, LUMA_LEVEL_PAL_SD/**/}, {TVE_ADJ_COMPOSITE_LUMA_LEVEL, SYS_525_LINE, LUMA_LEVEL_NTSC_SD/**/},
    {TVE_ADJ_COMPOSITE_CHRMA_LEVEL, SYS_625_LINE, CHRMA_LEVEL_PAL_SD/**/}, {TVE_ADJ_COMPOSITE_CHRMA_LEVEL, SYS_525_LINE, CHRMA_LEVEL_NTSC_SD/**/},
    {TVE_ADJ_PHASE_COMPENSATION, SYS_625_LINE, 0x0130}, {TVE_ADJ_PHASE_COMPENSATION, SYS_525_LINE, 0x07b0},
    {TVE_ADJ_VIDEO_FREQ_RESPONSE, SYS_625_LINE, FREQ_RESPONSE_PAL_SD/**/}, {TVE_ADJ_VIDEO_FREQ_RESPONSE, SYS_525_LINE, FREQ_RESPONSE_NTSC_SD/**/}, 
};


UINT8 scart_16_9_ratio = 0xFF;
void api_scart_aspect_callback(UINT8 b_widescr)
{
	scart_16_9_ratio = b_widescr;
}

static void vpo_dev_attach(void)
{

	struct VP_Feature_Config vp_config;
	struct Tve_Feature_Config tve_config;
    struct Tve_Feature_Config sd_tve_config;

	MEMSET((void *)&tve_config,0,sizeof(struct Tve_Feature_Config));
	MEMSET((void *)&sd_tve_config,0,sizeof(struct Tve_Feature_Config));
	MEMSET((void *)&vp_config,0,sizeof(struct VP_Feature_Config));

	vp_config.bAvoidMosaicByFreezScr = FALSE;    /* macro VDEC_AVOID_MOSAIC_BY_FREEZE_SCR */

    vp_config.bMHEG5Enable = FALSE;                  /* macro  _MHEG5_ENABLE_ */

	vp_config.bOsdMulitLayer = FALSE;                  /* macro OSD_MULTI_LAYER */
	vp_config.bOvershootSolution = FALSE;            /* macro VIDEO_OVERSHOOT_SOLUTION */
	vp_config.bP2NDisableMAF= TRUE;
	vp_config.bSupportExtraWin = FALSE;                /* macro VIDEO_SUPPORT_EXTRA_DVIEW_WINDOW */
	vp_config.bADPCMEnable= FALSE;                    /* macro VIDEO_ADPCM_ONOFF(VIDEO_ADPCM_ON:TRUE VIDEO_ADPCM_OFF:FALSE) */
	vp_config.pMPGetMemInfo = NULL;

	vp_config.pSrcAspRatioChange_CallBack = api_scart_aspect_callback;//api_Scart_Aspect_Switch;


    tve_config.config = YUV_SMPTE|TVE_TTX_BY_VBI|TVE_CC_BY_VBI;

    tve_config.config |= TVE_NEW_CONFIG_1;
    tve_config.tve_tbl_all = tve_table_total;


	vpo_m36f_attach(&vp_config, &tve_config);
    vcap_attach_t vcap_param;
    vcap_param.fb_addr = __MM_VCAP_FB_ADDR;
    vcap_param.fb_size = __MM_VCAP_FB_SIZE;
    vcap_m36f_attach(&vcap_param);
 
    sd_tve_config.config = YUV_SMPTE|TVE_TTX_BY_VBI|TVE_CC_BY_VBI;

    sd_tve_config.tve_adjust = g_sd_tve_adjust_table;
	vpo_m36f_sd_attach(&vp_config, &sd_tve_config);

}

void osal_delay_ms(UINT32 ms)
{
    UINT32 i;
    for (i = 0; i < ms; i++)
        osal_delay(1000);
}

void system_hw_init()
{
	HANDLE hVDec;	
    UINT32 data, reg ;

    if (sys_ic_get_chip_id() < ALI_S3602F)
    {
	    *(UINT32 *)0xb8000078 = (*(UINT32 *)0xb8000078 | 0x00000200);   /* for de */
    }
    else if (sys_ic_get_chip_id() == ALI_S3602F)
    {
        data = *(UINT32 *)0xb8001010;
        data &= ~(1<<18);   // DE
        data &= ~(1<<19);   // DE
        data &= ~(1<<20);   // VE
        data &= ~(1<<21);   // VE
        *(UINT32 *)0xb8001010 = data;
		*(UINT32 *)0xb8000004 = 1;
		
        data = *(UINT32 *)0xb8001024;
        data |= 0xffff;
        *(UINT32 *)0xb8001024 = data;

        data = *(UINT32 *)0xb8001020;
        data &= 0xffff;
        data |= 0x01080000;
        *(UINT32 *)0xb8001020 = data;

    }
    osal_delay_ms(10);

    vpo_dev_attach();
    vdec_dev_attach();


}

UINT8 api_get_chunk_add_len(UINT32 id,UINT32* addr,UINT32* len)
{
	INT32 ret;
	CHUNK_HEADER chuck_hdr;

	ret = sto_get_chunk_header(id,&chuck_hdr);
	if(ret==0)
		return 0;

	*addr = (UINT32)sto_chunk_goto(&id,0xFFFFFFFF,1) + CHUNK_HEADER_SIZE;
	*len = chuck_hdr.len - CHUNK_HEADER_SIZE + CHUNK_NAME;

	return 1;
}

void api_show_bootup_logo(void)
{
    	int i;    
	void* pWriteBuffer;
    	UINT32 uSizeGot;
	RET_CODE ret_code;
    	UINT32 logo_id,addr,len;   
	struct sto_device *sto_flash_dev;

    UINT8 *logo_buf;


    logo_id = BOOT_LOGO_ID;
    if(api_get_chunk_add_len(logo_id,&addr,&len) ==0 )
        return;
 
     logo_buf = (UINT8 *)MALLOC(len);

    //screen_back_state = SCREEN_BACK_MENU;
        
    ret_code = vdec_start(g_decv_dev);
	sto_flash_dev = (struct sto_device *)dev_get_by_id(HLD_DEV_TYPE_STO, 0);

	for(i=0;i<4;i++)
	{
		ret_code = vdec_vbv_request(g_decv_dev,len,	&pWriteBuffer,&uSizeGot,NULL);
           
    	sto_get_data(sto_flash_dev, (UINT8 *)logo_buf, addr, uSizeGot);
        MEMCPY(pWriteBuffer,logo_buf,uSizeGot);

		vdec_vbv_update(g_decv_dev, uSizeGot);
	}
   
    FREE(logo_buf);

}

#define VOU_CTRL      (*((volatile UINT32*)(0xb8006000)))
#define VOU_CFG_HDMI  (*((volatile UINT32*)(0xb8006080)))
/***********************For BootLogo add**********************/
void AppInit(void)
{
	union BOOT_INFO *boot_info;
	static UINT8 pos;
    UINT8 ch;
	UINT32 boot_tick,chid,offset;
	UINT8 *main_entry,*see_entry;
	UINT8  boot_type;
	UINT32 boot_code;
	UINT32 decryp_flag = 0xff;			
	UINT32 cpu_mc_len=0, see_mc_len=0, ota_len=0;
	UINT32 ota_backup_addr,ota_backup_len;
    UINT32 ziped_len = 0;
	UINT8 *p;
    UINT32 block_addr = 0, block_len = 0;
    static UINT8 *temp_buffer = NULL;
    static UINT8 *main_code = NULL;
    static UINT8 *see_code = NULL;
    static UINT8 *ota_decrypted = NULL;
	struct de2Hdmi_video_infor LlvS;
    LlvS.tv_mode = 10;
    LlvS.afd_present = TRUE;
    LlvS.scan_mode = FALSE;
	LlvS.format = 4;
	LlvS.output_aspect_ratio = 0;
	LlvS.active_format_aspect_ratio = 8;
	LlvS.width = 1920;
	LlvS.height = 1080;
	LlvS.av_chg_ste = HDMI_CB_NOTHING;

	temp_buffer = (UINT8*)(0xa0000000|(0xFFFFFFF8&(UINT32)MALLOC(__SEE_ROM_END - __SEE_ROM_START+0xf)));

    bl_GPIO_init();
#if (SYS_MAIN_BOARD == BOARD_DB_M3601E_02V01) 
 	*((unsigned long *)0xb8000438)=(*((unsigned long *)0xb8000438))|0x01;
 #endif
    /* Copy Mini See */
	MEMCPY((UINT8 *)(temp_buffer), __SEE_ROM_START, (__SEE_ROM_END - __SEE_ROM_START));

	//See Self boot 
	self_boot(SEE_ENTRY, temp_buffer, (__SEE_ROM_END - __SEE_ROM_START), SEE_ENTRY);

    FREE(temp_buffer);
	boot_code = *(UINT32 *)(0xA0000110);
	/* Cold bootup */
	boot_type = *(UINT8 *)(SYS_FLASH_BASE_ADDR + HW_SET_BOOTTYPE);
	if ((boot_type & BOOT_TYPE_MASK) && boot_code == 0xdead3bee)
	{
	    /* If cold bootup and enter standby enabled, enter standby */
		sys_ic_enter_standby(0, 0);
	}

	/************       Initialize      ***********************/
    bl_init_uart();
    bl_init_panel();
    bl_init_flash();
	//see_step1();
    MG_Setup_CRC_Table();
    g_crc_bad = check_program();
	system_hw_init();
	avInit();
	avStart();
    api_show_bootup_logo();
    hdmi_show_on_bootloader(&LlvS);	
	
	/************config_de**************/	
    VOU_CTRL = VOU_CTRL&(~(1<<2));	
	osal_delay(5);
	VOU_CFG_HDMI = VOU_CFG_HDMI|(1<<20);
	osal_delay(5);
	VOU_CFG_HDMI = VOU_CFG_HDMI |0x02;
	osal_delay(5);	
	VOU_CTRL = VOU_CTRL|(1<<2)|0x01;
	/**************config_de*************/
	if (0 == g_crc_bad) // normal boot, verify MainCode/SeeCode Signed
	{
		UINT8 sys_sw_wrong = 0;
		if(0 == api_get_chunk_add_len(CHUNKID_MAINCODE, &block_addr, &block_len))
		{
			FIXED_PRINTF("Can't find chunk id 0x%08x.\n", CHUNKID_MAINCODE);
		}
	    if(0!=block_len)
	    {
	        main_code = (UINT8*)(0xa0000000|(0xFFFFFFF8&(UINT32)MALLOC(block_len+0xf)));
			PRINTF_BOOTLOGO(main_code,flash_dev);
	        sto_get_data(flash_dev, main_code, block_addr, block_len);
#ifdef FIRMWARE_SIGN
		/*RSA verify maincode*/
		FIXED_PRINTF("start RSA verify maincode.\n");
	        if(0 == Test_RSA_Ram((unsigned int)main_code, block_len))
	   		{
	   			FIXED_PRINTF("maincode verify success,addr is:%x,len is:%x\n",main_code,block_len);
	   		}
	   		else
	   		{
	        	sys_sw_wrong = 1;
				FIXED_PRINTF("maincode verify failed.\n");
	   		}
#endif
		}
		else
		{
		    sys_sw_wrong = 1;
			FIXED_PRINTF("maincode len is zero.\n");        
		}
		
		if(sys_sw_wrong!=1)
		{
		  //get the block_len
			if(0 == api_get_chunk_add_len(CHUNKID_SEECODE, &block_addr, &block_len))
		    {
		    	FIXED_PRINTF("Can't find chunk id 0x%08x.\n", CHUNKID_MAINCODE);
		    }
		    else if(block_len != 0)
		    {
		       	see_code = (UINT8*)(0xa0000000|(0xFFFFFFF8&(UINT32)MALLOC(block_len+0xf)));
		        sto_get_data(flash_dev, see_code, block_addr, block_len);            
				PRINTF_BOOTLOGO(block_addr,block_len);
#ifdef FIRMWARE_SIGN
		        if(0 == Test_RSA_Ram((unsigned int)see_code, block_len))
#endif
		      	{
		        	//for decompress use.    
		          	g_see_unziped = (UINT8*)(0xa0000000|(0xFFFFFFF8&(UINT32)MALLOC(block_len*4)));              
		        	FIXED_PRINTF("seecode verify success,addr is:%x,len is:%x\n",see_code,block_len);
		        }
#ifdef FIRMWARE_SIGN
		        else
		        {
		        	sys_sw_wrong = 1;
		        	FIXED_PRINTF("seecode verify failed,addr is:%x,len is:%x\n",see_code,block_len);
		        }
#endif
			}
		}
		if(sys_sw_wrong==1)
		{
			FIXED_PRINTF("fw verify failed,enter otaloader\n");
		    hw_watchdog_reboot(); //loader code error, enter hw reboot
		}
    }
	else if(g_second_loader == 1)	// ota loader boot
	{
		block_len = sto_fetch_long(g_ota_offset + CHUNK_LENGTH) - CHUNK_HEADER_SIZE + CHUNK_NAME;
		main_code = (UINT8*)(0xa0000000|(0xFFFFFFF8&(UINT32)MALLOC(block_len+0xf)));
		sto_get_data(flash_dev, main_code, (g_ota_offset + CHUNK_HEADER_SIZE), block_len);					
		sto_chunk_init(g_ota_offset, flash_dev->totol_size - g_ota_offset);
		chid = CHUNKID_SECSEECODE;
		block_addr = sto_chunk_goto(&chid, CHUNKID_SECSEECODE_MASK, 1);
		block_len = sto_fetch_long(block_addr + CHUNK_LENGTH) - CHUNK_HEADER_SIZE + CHUNK_NAME;
		see_code = (UINT8*)(0xa0000000|(0xFFFFFFF8&(UINT32)MALLOC(block_len+0xf)));
		g_see_unziped = (UINT8*)(0xa0000000|(0xFFFFFFF8&(UINT32)MALLOC(block_len*4)));
		sto_get_data(flash_dev, see_code, (block_addr + CHUNK_HEADER_SIZE), block_len);
		sto_chunk_init(0, flash_dev->totol_size);        
  	}
  	else
  	{
      FIXED_PRINTF("crc bad and no secloader!\n");
      hw_watchdog_reboot(); //loader code error, enter hw reboot
  	}
    if(g_vpo_dev != NULL)
        vpo_win_onoff(g_vpo_dev,0);
    if(g_sd_vpo_dev != NULL)
        vpo_win_onoff(g_sd_vpo_dev, 0);
    
    *((volatile UINT8 *)0xb8000220) = 0;
    PRINTF_BOOTLOGO(see_code,see_mc_len);
    p = see_code+(see_mc_len-0x200);
    ziped_len = p[3]|(p[2] << 8) |(p[1] << 16)|(p[0] << 24);
    //enter Maincode
    PRINTF_BOOTLOGO(p,ziped_len);
    FIXED_PRINTF("expand see main code, ziped len: %x\n", ziped_len);
    see_entry = expand_ram(see_code, ziped_len, un7zip, SEE_CODE);
    if(see_entry)
    {
    	FIXED_PRINTF("success, unziped len: 0x%x,see entry = 0x%x,\n", unzip_length,see_entry);
    	self_boot(SEE_ENTRY, see_entry, unzip_length, 0);
    }
    PRINTF_BOOTLOGO(see_entry,see_entry);

    p = main_code+(cpu_mc_len-0x200);
    ziped_len = p[3]|(p[2] << 8) |(p[1] << 16)|(p[0] << 24);
    FIXED_PRINTF("expand cpu main code, ziped len: 0x%x\n", ziped_len);
    main_entry = expand_ram(main_code, ziped_len, un7zip, MAIN_CODE);

	PRINTF_BOOTLOGO(p,ziped_len);
    PRINTF_BOOTLOGO(main_entry,main_entry);
    if (main_entry != 0)
    {
    	FIXED_PRINTF("success, unziped len: %d.\n", unzip_length);
    	set_os_config(128,64,64,64,64);
    	FIXED_PRINTF("jump to fw entry=%x\n",main_entry);
    	exec(main_entry);
    }
}


